
class Strategy:
  def __init__(self, deposit=400000, price_per_point=200, commission=500):
    self.bars = None
    self.current_index = -1
    self.points_balance = 0
    self.entry_price = 0
    self.current_contracts = 0
    self.price_per_point = price_per_point
    self.commission = commission
    self.initial_deposit = deposit
    self.balance = deposit
    self.win = 0
    self.lose = 0
    
  def Buy(self, price):
    self.ExitShort(price)
    self.entry_price = price  
    self.current_contracts = 1
    #print "Buy @%d"%(price)
  
  def Sell(self, price):
    self.ExitLong(price)
    self.entry_price = price
    self.current_contracts = -1
    #print "Sell @%d"%(price)
    
  def ExitLong(self, price):
    if self.current_contracts > 0:
      points_balance = (price - self.entry_price)*self.current_contracts
      if points_balance>=0:
        self.win += 1
      else:
        self.lose += 1
      print "ExitLong: %d points (%d -> %d)"%(points_balance, self.entry_price, price)
      self.points_balance += points_balance
      self.balance += points_balance * self.price_per_point - self.commission
      self.current_contracts = 0
    
  def ExitShort(self, price):
    if self.current_contracts < 0:
      points_balance = (price - self.entry_price)*self.current_contracts
      if points_balance<=0:
        self.win += 1
      else:
        self.lose += 1
      print "ExitShort: %d points (%d -> %d)"%(points_balance, self.entry_price, price)
      self.points_balance += points_balance
      self.balance += points_balance * self.price_per_point - self.commission
      self.current_contracts = 0
      
  def ShowResults(self):
    self.ExitLong(self.Close(0))
    self.ExitShort(self.Close(0))
    transaction = self.lose+self.win
    print "--------------- Performance Report ------------------"
    print "%d Transaction, Win=%d (%.1f%%), Lose=%d(%.1f%%)"%(\
      transaction, self.win, self.win*100/transaction, self.lose, self.lose*100/transaction)
    print "Initial deposit=%d"%(self.initial_deposit)
    print "points_balance is %d points, equals to %d (NTD)"%\
          (self.points_balance, self.points_balance*self.price_per_point)
    print "commission is %d"%(self.balance-self.initial_deposit-self.points_balance*self.price_per_point)
    print "Final balance is %d"%(self.balance)
    print "Actual earning is %d"%(self.balance-self.initial_deposit) 
    print "--------------- Performance Report ------------------"    
    
  def CrossOver(self, a, b):
    #prev a < prev b and current a > current b
    print "[%s] Close=%d, Fast[-1](%d)<Slow[-1](%d) and Fast(%d)>=Slow(%d) ? %d"%(self.bars[self.current_index].time, \
        self.bars[self.current_index].close, a(1),b(1),a(0),b(0), a(1)<b(1) and a(0)>=b(0))
    return a(1)<b(1) and a(0)>=b(0)
    
  def Close(self, offset=0):
    if self.current_index < offset:
      return 0
    else:
      return self.bars[self.current_index - offset].close
    
  def Open(self, offset=0):
    if self.current_index < offset:
      return 0
    else:
      return self.bars[self.current_index - offset].open

  def High(self, offset=0):
    if self.current_index < offset:
      return 0
    else:
      return self.bars[self.current_index - offset].high
    
  def Low(self, offset=0):
    if self.current_index < offset:
      return 0
    else:
      return self.bars[self.current_index - offset].low
  
  def Sum(self, f, count, offset=0):
    sum = 0
    if self.current_index < offset:
      return sum
    elif self.current_index < offset + count:
      count = self.current_index-offset
    for e in map(f, range(offset, count+offset)):
      #print "sum(%d) += %d"%(sum, e)
      sum += e
    #print "[%d] Sum(count=%d, offset=%d)=%d"%(self.current_index, count, offset, sum)
    return sum
    
  def Average(self, f, count, offset=0):
    avg = 0
    if self.current_index < offset:
      return 0
    elif self.current_index < offset + count:
      count = self.current_index-offset
      
    if count == 0:
      return 0
      
    avg = self.Sum(f, count, offset)/count
    #print "[%d] Average(count=%d, offset=%d)=%d"%(self.current_index, count, offset, avg)
    return avg

  def Run(self, Open, High, Low, Close):
    pass
    
  def RunWithBars(self, bars):
    self.bars = bars
    self.count = len(bars)
    for i in range(0, self.count):
      self.current_index = i
      #print "[%d][%s] %d %d %d %d"%(i, self.bars[i].time, self.bars[i].open, \
        #self.bars[i].high, self.bars[i].low, self.bars[i].close)
      self.Run(lambda x: self.Open(x), \
               lambda x: self.High(x), \
               lambda x: self.Low(x), \
               lambda x: self.Close(x))
              
    self.ShowResults()